package main

import (
	"fmt"
	"net"
	"sync"
	"io"
	"time"
)

//首先写一个server类
type Server struct{
	//ip地址
	Ip string
	//端口
	Port int
	//用户map，存储哪些用户在线
	OnlineMap map[string]*User
	//设置一个锁，用来控制对于用户map的访问
	mapLock sync.RWMutex
	//消息队列，一旦里面有消息，就把消息广播給每个用户
	Message chan string
}
func NewServer(ip string,port int) *Server{
	server := &Server{
		Ip:ip,
		Port:port,
		OnlineMap:make(map[string]*User),
		Message: make(chan string),
	}
	return server
}


//广播消息,把消息放入消息队列
func (this *Server) BroadCast(user *User,msg string){
	sendMsg := "["+user.Addr+"]"+user.Name+":"+msg
	fmt.Println(sendMsg)
	this.Message <-sendMsg
}


//处理当前连接
func (this *Server) Handler(conn net.Conn) {
	//处理当前连接的业务
	//fmt.Printf("ip%s端口%d已连接",this.Ip,this.Port)
	// res := make([]byte, 5)
	// _, err := conn.Read(res)
	// if err != nil {
	// 	fmt.Println("接收消息错误")
	// }
	// fmt.Printf("消息是:%s\n",string(res))
	//用户上线，创建一个用户对象
	user := NewUser(conn,this)
	//用户上线
	user.OnLine()

	//设置一个管道判断用户是否活跃
	isLive := make(chan bool)

	//广播用户的消息，实现群聊功能
	go func(){
		//开一块空间存消息,大小为4096
		buf := make([]byte, 300)
		//循环读取信息
		for {
			//两个返回值，n为读取的消息长度，err为错误信息
			n,err := conn.Read(buf)
			if n == 0 {
				//用户下线
				user.OffLine()
				return
			}
			if err != nil && err != io.EOF{
				fmt.Println("消息读取错误")
				return
			}
			//提取用户消息，把"\n"去掉
			msg := string(buf[:n-1])
			// msg := string(buf)
			//广播用户消息
			user.DoMessage(msg)
			//一旦用户活跃就往isLive中放东西
			isLive <- true
		}
	}()
	//阻塞当前Handler
	//实现超时强踢功能
	for {
		select {
		case <-isLive:
			//从isLive中取东西
			//如果取到了，说明用户活跃，则会执行下面的case，重置定时器
		case <- time.After(time.Second * 300):
			//上面的相当于一个管道，如果有数据读出来说明已经到时间了，应该踢
			//处理踢用户操作
			user.SendCli("你被踢了!")
			//关闭用户管道
			close(user.C)
			//关闭用户连接
			conn.Close()
			//退出当前Handler
			return
		}
	}

}

//设置一个协程监视消息队列，一旦有内容就广播給每个用户
func (this *Server) ListenMessager(){
	for {
		//从Messager中取消息
		msg := <-this.Message
		//发送給所有在线用户
		//访问在线用户列表要加锁
		this.mapLock.Lock()
		for _, userPoint := range this.OnlineMap{
			userPoint.C <-msg
		}
		this.mapLock.Unlock()
	}
}

func (this *Server) Start(){
	//Listen创建一个socket
	listener, err :=net.Listen("tcp",fmt.Sprintf("%s:%d",this.Ip,this.Port))
	if err != nil {
		fmt.Println("创建socket失败",err)
		return
	}
	//关闭socket
	defer listener.Close()

	go this.ListenMessager()
	for {
		//accept
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("创建连接失败",err)
			continue
		}
		//开一个协程去处理这个连接的业务
		go this.Handler(conn)
	}

}